package com.xcc.server;

import com.xcc.server.decoder.MessageDecoder;
import com.xcc.server.domains.vo.Message;
import com.xcc.server.encoder.MessageEncoder;
import com.xcc.server.hadler.ServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.CharsetUtil;

import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Carman
 * @date 2021/2/4 17:35
 * @desc 服务端
 */
public class Server {

    public static final ConcurrentHashMap<String, ChannelHandlerContext> CHANNEL_MAP = new ConcurrentHashMap();

    private NioEventLoopGroup bossGroup;
    private NioEventLoopGroup workerGroup;
    private ServerBootstrap serverBootstrap;
    private ChannelFuture future;
    private int port = 9;

    public Server(int port) {
        this.bossGroup = new NioEventLoopGroup();
        this.workerGroup = new NioEventLoopGroup();
        this.port = port;
        serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<Channel>() {

                    @Override
                    protected void initChannel(Channel ch) throws Exception {
                        ch.pipeline()
                                // 每个新连接都会执行一次
//                        .addLast(new DelimiterBasedFrameDecoder(4096, Delimiters.lineDelimiter()))
//                                    .addLast(new MyIdleStateHandler(5, 0, 0, TimeUnit.SECONDS))
                                .addLast(new LineBasedFrameDecoder(1024))
                                .addLast(new MessageDecoder(CharsetUtil.UTF_8))  // 解码
                                .addLast(new MessageEncoder(CharsetUtil.UTF_8))  // 编码
//                                    .addLast(new LoggingHandler(LogLevel.INFO)) //打印日志
                                .addLast(new ServerHandler());
                    }
                });
    }

    public void start() throws InterruptedException {
        System.out.println("开始监听");
        try {
            future = serverBootstrap.bind(port).sync();
            future.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
        }
    }

    public void close() throws InterruptedException {
        if (null != bossGroup) {
            bossGroup.shutdownGracefully().sync();
        }
        if (null != workerGroup) {
            workerGroup.shutdownGracefully().sync();
        }
    }

    public ChannelFuture sendMessage(String userId, Message<?> message) {
        ChannelHandlerContext channelHandlerContext = CHANNEL_MAP.get(userId);
        if (null == channelHandlerContext) {
            throw new NullPointerException("未获取到连接对象");
        }
        Channel channel = channelHandlerContext.channel();
        return channel.writeAndFlush(message);
    }
}
